package messagepasser;

/**
 * 
 * @author Rishit Shroff(rshroff)
 * @author Huimin Yang(huiminy)
 * @description Contains the description of the Logger class 
 */

import java.io.*;
import java.net.Socket;
import java.util.Timer;

/**
 * 
 * Handle a received message, put it into the inputBuffer
 * 
 * @see ListenSocket
 *
 */
class ReceiveSocket extends Thread  {

	Message message;					// received Message
	MessagePasser msgPasser;			// reference to MessagePasser Object
	ObjectInputStream inObjectStream;	// Input Object Stream
	Socket connection;					// Connection Socket

	/**
	 * Parameterized Constructor
	 * @param socket
	 * @param m			reference to the message Passer object
	 */
	ReceiveSocket ( Socket socket, MessagePasser m)  {
		super ();
		connection =  socket;
		msgPasser = m;
	}

	/**
	 *  Run method
	 */

	public void run  ()  {

		try  {
			inObjectStream = new ObjectInputStream (connection.getInputStream ());
			//debug
			// loop to read the incoming messages
			while ( true )  {

				message = (Message)inObjectStream.readObject();
				if (message.getPayload() == null) {
						System.out.println("socket receive null payload");
				} else {
						System.out.println("socket receive payload == " + message.getPayload());
				}

				synchronized (msgPasser) {
					//check for drop and delay types
					//Lab1
					TimeStampedMessage msg = (TimeStampedMessage)message;
					if(msgPasser.getMyName().equals("logger") == false) {
						if (message.isMulticastMsg()) {

							// debug
							//			System.out.println("Socket recv multi, physical sender is " + msg.getPhySender());

							if(msg.getMsgType().contains("ack")) {
								//debug
								//			System.out.println("Got ack from " + msg.getHeader().getSrc());
								msgPasser.updateAckOfMsg(msg);
								return;
							}
							if(msg.getMsgType().equals("ok")) {
								//debug
								//		System.out.println("Got ok from " + msg.getHeader().getSrc());
								msgPasser.moveToInputBuffer(msg);
								return;
							}
							else {

								// network drop delay duplicate simulation
								String process = msgPasser.findOp(message);
								if (process.equals("drop")) {
									return;
									// message is dropped and never delivered
								} else if (process.equals("delay")) {
									msgPasser.addToNetworkBuffer(message);
								} else if (process.equals("duplicate")) {
									// add twice
									msgPasser.addToReadyBuffer(message);
									msgPasser.networkToReady(); //probably delayed message
									msgPasser.addToReadyBuffer(message);
								} else {
									msgPasser.addToReadyBuffer(message);
									msgPasser.networkToReady();
								}

								if (msgPasser.readyToReceive()) {
									for ( Message readyMessage : msgPasser.getReadyBuffer()) {
										msgPasser.acceptRealMessage((TimeStampedMessage)readyMessage);
									}
									msgPasser.emptyReadyBuffer();

								}
							}
						} 
						else {

							
							
							msgPasser.recvStamp((TimeStampedMessage)message);
							msgPasser.getInputBuffer().add(message);
						}
					}
				}
				message = null;
			}  
		}
		catch ( Exception except ) {
			try  {
				connection.close ();
				return;
			}
			catch ( Exception e )  {
				e.printStackTrace ();
				return;
			}
		}
	}
}
